home *** CD-ROM | disk | FTP | other *** search
- /* -----------------------------------------------------------------------------------
- -----------------------------------------------------------------------------------
- SWTinting.c
-
- by Brian Roddy
-
- 4/3/97
-
-
- - Functions for tinting SpriteWorld graphics a particular color.
- - Functions for using tinting to implement basic lighting techniques on
- sprites and tiles.
-
- This style of lighting works well with tiles with a single kind of light. This
- is because we precompute all of the sprites and tiles at the different light
- levels. This makes it fast, but not very flexible. See "SWLightingSquares.c"
- for another approach to lighting which is slightly slower, but is dynamic and
- handles an arbitrary number of colored lights.
-
- This source code is available for free use.
-
- -----------------------------------------------------------------------------------
- ----------------------------------------------------------------------------------- */
-
- #include <QDOffScreen.h>
- #include "SpriteWorldUtils.h"
- #include "SWTinting.h"
-
-
- /* --- SWTintFrame
-
- This function takes a frame and uses a color to tint the sprite's frame by some
- percent. The tint is specified by an RGBColor. The percent is a number from 0-100.
- For instance, to lighten a sprite a little bit, use white as a color and 10 as a
- percent.
-
- These functions perform some basic error checking and will return the error if found.
-
- */
-
- SW_FUNC OSErr SWTintFrame (
- FramePtr srcFrameP,
- RGBColor* tint,
- float percent)
- {
- GWorldPtr oldGWld;
- GDHandle oldGDH;
- GWorldFlags pixelState;
- RGBColor opColor;
- OSErr err = noErr;
-
- // Make sure we have an actual frame
- if (srcFrameP->framePort == NULL)
- err = paramErr;
-
- if (err == noErr) {
- // Save all current information.
- GetGWorld( &oldGWld, &oldGDH );
-
- // Save the pixel state of our bitmap's GWorld
- pixelState = GetPixelsState( GetGWorldPixMap( srcFrameP->framePort ));
- (void)LockPixels( GetGWorldPixMap( srcFrameP->framePort ));
- SetGWorld( srcFrameP->framePort, NULL );
-
- // And then blend in the Sprite image it's appropriate percent.
- // Opcolor specifies the amount of blend
- opColor.red = opColor.blue = opColor.green = (((percent) * 65535.0) / 100.0);
- OpColor(&opColor);
-
- // Paint the Sprite the color specified by tint.
- RGBForeColor(tint);
-
- // Blend will do the work of tinting
- PenMode(blend);
-
- // And then paint it to tint the frame.
- // If there is a mask, then just tint the masked part of the frame.
- if (srcFrameP->maskRgn != NULL)
- PaintRgn(srcFrameP->maskRgn);
- // Otherwise tint the entire frame
- else
- PaintRect(&srcFrameP->frameRect);
-
- //Restore the state of the world.
- PenNormal();
- SetPixelsState( GetGWorldPixMap( srcFrameP->framePort ), pixelState );
- SetGWorld( oldGWld, oldGDH );
- }
-
- SWSetStickyIfError( err );
- return err;
- }
-
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
- /// Tile Light Level Functions
- ///--------------------------------------------------------------------------------------
- short backgroundTileMinimumLightLevel = 0;
-
- /* -- CreateTileBrightnessSetFromCicnResource --
-
- This function is the same as SWLoadTileFromCicnResource except that it will
- create a set of tiles rather than one. Each tile represents the original tile at a
- different light level. It uses the SWTintFrame to do this. Each tile will
- get successively brighter until reaching the original tile.
-
- */
-
- SW_FUNC OSErr CreateTileBrightnessSetFromCicnResource (
- SpriteWorldPtr swp,
- short baseTileID,
- short cicnID,
- MaskType maskType) {
-
- OSErr err = noErr;
- RGBColor tintColor;
- int i;
- float ratio;
-
- // Our tint color is black because we make darker versions of the tile
- tintColor.red = tintColor.green = tintColor.blue = 0;
-
- // For each of the different light levels
- for (i = 0; i < kNumberOfBrightnessLevels; i++) {
- if (err == noErr) {
- // Create tile normally
- err = SWLoadTileFromCicnResource(swp, baseTileID + i, cicnID, maskType);
-
- // And then tint it.
- ratio = ((i + 1.0) / kNumberOfBrightnessLevels);
- if ((err == noErr) && (ratio != 1.0)) {
- err = SWTintFrame(
- swp->tileFrameArray[baseTileID + i],
- &tintColor,
- 100 - (ratio * 100));
- }
- }
- }
-
- SWSetStickyIfError( err );
- return err;
- }
-
-
- ///--------------------------------------------------------------------------------------
- /// GetTileBrightnessLevel
- ///
- /// Returns a particular tile on the screens light level.
- /// Remember that the light level is encoded in the tile's id.
-
- SW_FUNC int GetTileBrightnessLevel (SpriteWorldPtr swp, short tileLayer, int row, int col) {
- int curTileID;
- // Compute the current Light level by dividing by
- // kNumberOfBrightnessLevels and taking the remainder.
- curTileID = swp->tileLayerArray[tileLayer]->tileMap[row][col];
- return (curTileID % kNumberOfBrightnessLevels);
- }
-
- ///--------------------------------------------------------------------------------------
- /// SetTileBrightnessLevel
- ///
- /// Sets the light level of a particular tile on the screens.
- /// Remember that the light level is encoded in the tile's id.
-
- SW_FUNC void SetTileBrightnessLevel (SpriteWorldPtr swp, short tileLayer, int row, int col,
- int level, Boolean relative) {
- int curTileID;
- int oldLightLevel;
- int tileWithoutLight;
- int newLightLevel;
- int newTileID;
-
- // Bounds checking of row and colums.
- if (! ((row < 0) ||
- (col < 0) ||
- (row >= swp->tileLayerArray[tileLayer]->numRows) ||
- (col >= swp->tileLayerArray[tileLayer]->numCols)) ) {
-
- // Given the current TileID
- curTileID = swp->tileLayerArray[tileLayer]->tileMap[row][col];
-
- // Compute the current Light level by dividing by
- // kNumberOfBrightnessLevels and taking the remainder.
- oldLightLevel = curTileID % kNumberOfBrightnessLevels;
-
- // Subtracting the remainder will leave us with the
- // tile id without light (i.e. the tile at light level zero)
- tileWithoutLight = curTileID - oldLightLevel;
-
- // If relative, add the new level to the old.
- // Of course if the new level is negative it will lower the light.
- if (relative)
- newLightLevel = oldLightLevel + level;
- else
- // Otherwise, set the light to the maximum of the new or the old.
- newLightLevel = ((level > oldLightLevel) ? level : oldLightLevel);
-
- // Bounds checking of light level
- if (newLightLevel < 0)
- newLightLevel = 0;
- else if (newLightLevel >= kNumberOfBrightnessLevels) {
- newLightLevel = kNumberOfBrightnessLevels - 1;
- }
- if (newLightLevel < backgroundTileMinimumLightLevel)
- newLightLevel = backgroundTileMinimumLightLevel;
-
- // Compute the new tile ID by combining our raw tile id and
- // the new light level.
- newTileID = tileWithoutLight + newLightLevel;
- swp->tileLayerArray[tileLayer]->tileMap[row][col] = newTileID;
-
- // Then redraw the tile
- SWDrawTile(swp, tileLayer, row, col, newTileID);
- }
- return;
- }
-
- ///--------------------------------------------------------------------------------------
- ///---- LowerTileBrightnessLevels.
- ///
- /// A utility function to do light fading over time. Looks pretty neat.
-
- SW_FUNC void LowerTileBrightnessLevels (SpriteWorldPtr swp) {
- short tileRow, tileCol, tileLayer;
- int numrows = swp->tileLayerArray[0]->numRows;
- int numcols = swp->tileLayerArray[0]->numCols;
-
- // Go through every TileMap in the SpriteWorld
- for (tileLayer = 0; tileLayer <= swp->lastActiveTileLayer; tileLayer++)
- {
- if (swp->tileLayerArray[tileLayer] == NULL)
- continue;
-
- // Go through every row
- for (tileRow = 0; tileRow < numrows; tileRow++)
- {
- // and column in the tile map
- for (tileCol = 0; tileCol < numcols; tileCol++)
- {
- // and lower it by 1.
- if (GetTileBrightnessLevel(swp, tileLayer, tileRow, tileCol) >
- backgroundTileMinimumLightLevel)
- {
- SetTileBrightnessLevel(swp, tileLayer, tileRow, tileCol, -1, true);
- }
- }
- }
- }
- }
-
-
-
-
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
- // Sprite Light Level Functions.
- ///--------------------------------------------------------------------------------------
-
-
- /* -- CreateSpriteBrightnessSetFromCicnResource --
-
- This function is the same as SWCreateSpriteFromCicnResource except that it will
- create multiple frames for the same sprite where each frame represents a
- different light level. It uses SWTintFrame to do this. Each frame will
- get successively brighter until reaching the original sprite's light level.
-
- */
-
- // Note that this code is a modified version of SWCreateSpriteFromCicnResource.
- SW_FUNC OSErr CreateSpriteBrightnessSetFromCicnResource (
- SpriteWorldPtr destSpriteWorld,
- SpritePtr* newSpriteP,
- void* spriteStorageP,
- short cIconID,
- MaskType maskType) {
-
- OSErr err;
- SpritePtr tempSpriteP;
- FramePtr newFrameP;
- short frame;
-
- // Change #1: Our two new variables
- RGBColor tintColor;
- float ratio;
-
- // Change #2: We specify a Tint Color.
- // Our tint color is black because we make are making
- // darker versions of the sprite
- tintColor.red = tintColor.green = tintColor.blue = 0;
-
- *newSpriteP = NULL;
-
- err = SWCreateSprite(&tempSpriteP, spriteStorageP, kNumberOfBrightnessLevels);
-
- if (err == noErr)
- {
- // Change #3: number of frames we make is kNumberOfBrightnessLevels
- // That is, one frame per brightness level
- for (frame = 0; frame < kNumberOfBrightnessLevels; frame++)
- {
- err = SWCreateFrameFromCicnResource(
- destSpriteWorld,
- &newFrameP,
- cIconID, // Change #4: All sprites use the same cicn.
- maskType);
-
- if (err == noErr)
- err = SWAddFrame(tempSpriteP, newFrameP);
-
- // Change #5: Here we do the actual tinting. We calculate
- // the current percent of brightness and call our tinting
- // function.
- ratio = ((frame + 1.0) / kNumberOfBrightnessLevels);
- if ((err == noErr) && (ratio != 1.0))
- err = SWTintFrame(
- tempSpriteP->frameArray[frame],
- &tintColor,
- 100 - (ratio * 100));
-
- if (err != noErr)
- {
- SWDisposeFrame(&newFrameP);
- SWDisposeSprite(&tempSpriteP);
- break;
- }
- }
-
- if (err == noErr)
- {
- SWSetSpriteFrameRange(tempSpriteP, 0, kNumberOfBrightnessLevels - 1);
- SWSetCurrentFrameIndex(tempSpriteP, 0);
- *newSpriteP = tempSpriteP;
- }
- }
-
- SWSetStickyIfError( err );
- return err;
- }
-
- ///--------------------------------------------------------------------------------------
- /// The Light Level is encoded in the frame index, so setting and getting it is easy.
- SW_FUNC int GetSpriteBrightnessLevel (SpritePtr spriteP) {
- return spriteP->curFrameIndex;
- }
-
- SW_FUNC void SetSpriteBrightnessLevel (SpritePtr spriteP, int tileLightLevel) {
- SWSetCurrentFrameIndex(spriteP, tileLightLevel);
- return;
- }
-